import random
import datetime
import json
import string
from gmssl import sm2
import base64
from Crypto.Cipher import AES

try:
    from urllib.parse import urlencode
except Exception as e:
    from urllib import urlencode
from .base import BaseYLClient
from finance_c2c.local_settings import YLappId, YLappKey, YLMid, YLTid, msgSrcId, YLnotifyUrl, YLBaseUrl, YLTokenKey, \
    ONLINE, YLMininotifyUrl, YLAppNotifyUrl
from core.tools.func_utils import FuncUtils
from core.wchat.wx_base import mc
from core.tools.encryption import hashlib_md5, sha256hex
from core.tools.custom_requests import CustomRequests

BLOCK_SIZE = AES.block_size
unpad = lambda s: s[:-ord(s[len(s) - 1:])]


class YLClient(BaseYLClient):
    def __init__(self):
        self.appid = YLappId
        self.app_key = YLappKey
        self.mid = YLMid
        self.tid = YLTid
        self.msgSrcId = msgSrcId
        self.nonce = self.nonce_str(length=64)
        self.now_time = lambda x: datetime.datetime.now().strftime(x)
        self.base_url = YLBaseUrl

    def nonce_str(self, length=32):
        """
        随机字符串，不长于32位
        :param length:
        :return:
        """
        chars = "abcdefghijklmnopqrstuvwxyz0123456789"
        strs = []
        for x in range(length):
            strs.append(chars[random.randrange(0, len(chars))])
        return "".join(strs)

    # 获取token
    def get_token_from_mc(self):
        if not mc.get(YLTokenKey):
            print("not mc ", YLTokenKey)
            response = self.get_token()
            print(response)
            if response.get("errCode") == "0000":
                accessToken = response.get("accessToken")
                expiresIn = 3600 - 60
                mc.set(YLTokenKey, accessToken, expiresIn)
                return accessToken
            else:
                raise Exception("获取银联token错误")
        else:
            print("mc get ", YLTokenKey)
            token = mc.get(YLTokenKey)
            print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "token,mc:", token)
            return token

    def get_token(self):
        url = "/v1/token/access"
        timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")  # 报文请求时间
        signature = self.sha256_hex(self.appid + timestamp + self.nonce + self.app_key)
        data = {"timestamp": timestamp, "signature": signature, "appId": self.appid, "nonce": self.nonce,
                "signMethod": "SHA256"}
        print(data)
        content = self.post(url, json=data)
        # {'errCode': '0000', 'errInfo': '正常', 'accessToken': 'c0ace90f19894c6297ccd1598ad5fa4f', 'expiresIn': 3600}
        return content

    def refund(self, merOrderId, refundAmount, refundOrderId, now_time):
        """
        退款
        :param merOrderId:  原交易订单号
        :param refundAmount: 退款金额
        :param refundOrderId: 退款订单号
        :return:
        """
        url = "/v1/netpay/refund"
        Authorization = self.get_token_from_mc()
        header = dict()
        header["Authorization"] = "OPEN-ACCESS-TOKEN AccessToken=" + Authorization
        content = {
            "merOrderId": merOrderId,
            "instMid": "YUEDANDEFAULT",
            "mid": self.mid,
            "tid": self.tid,
            "refundAmount": refundAmount,
            "refundOrderId": refundOrderId,
            "requestTimestamp": now_time.strftime("%Y-%m-%d %H:%M:%S")
        }
        print(content, "yl refund")
        return self.post(url, json=content, headers=header)

    @property
    def unique_value(self):
        if ONLINE:
            return "6679" + FuncUtils().unique_value  # 外部订单号
        return "1017" + FuncUtils().unique_value  # 外部订单号

    @property
    def new_unique_value(self):
        u_value = self.unique_value
        s = string.ascii_letters
        r = random.sample(s, 3)
        v = u_value + "".join(r)
        return v

    def pay(self, srcReserve, orderDesc, totalAmount, redirect_url, pay_type=0, merOrderId=None):
        """
        :param srcReserve: 请求系统预留字段
        :param orderDesc: 账单描述
        :param totalAmount: 支付金额
        :param redirect_url: 前端重定向结果页
        :param pay_type: 支付类型
        :param merOrderId: 订单号
        :return:
        """
        url = self.base_url + "/v1/netpay/webpay/pay"
        now_time = datetime.datetime.now()
        timestamp = now_time.strftime("%Y%m%d%H%M%S")
        requestTimestamp = now_time.strftime("%Y-%m-%d %H:%M:%S")
        nonce = self.nonce_str(32)
        if not merOrderId:
            merOrderId = self.unique_value  # 外部订单号
        data = {'authorization': 'OPEN-FORM-PARAM', 'appId': self.appid,
                'timestamp': timestamp, 'nonce': nonce
                }
        content = {"msgId": "001", "requestTimestamp": requestTimestamp,
                   "merOrderId": merOrderId, "srcReserve": srcReserve, "mid": self.mid,
                   "tid": self.tid, "instMid": "YUEDANDEFAULT", "orderDesc": orderDesc, "totalAmount": totalAmount,
                   "notifyUrl": YLnotifyUrl, "returnUrl": redirect_url}
        if pay_type == 3:  # 这里不需要(商城还在用)
            url = self.base_url + "/v1/netpay/trade/create"
            content["tradeType"] = "JSAPI"
        content = self.custome_json(content)
        body_digest = self.sha256_hex(content)
        str_content = self.appid + timestamp + nonce + body_digest
        signature = self.HmacSHA256(str_content, self.app_key)
        data["content"] = content
        data["signature"] = signature
        param = urlencode(data)
        print(data, "银联支付请求参数 data")
        print(param, "银联支付请求参数")
        pay_url = "{url}?{param}".format(**{"url": url, "param": param})
        print(pay_url, "支付链接")
        return pay_url, merOrderId

    def query(self, merOrderId):
        """
        要查询的订单号
        :param merOrderId:
        :return:
        """
        url = "/v1/netpay/query"
        content = {"requestTimestamp": self.now_time("%Y-%m-%d %H:%M:%S"),
                   "mid": self.mid,
                   "merOrderId": merOrderId,
                   "tid": self.tid,
                   "instMid": "YUEDANDEFAULT"
                   }
        Authorization = self.get_token_from_mc()
        header = {
            "Authorization": "OPEN-ACCESS-TOKEN AccessToken=" + Authorization
        }
        return self.post(url, json=content, headers=header)

    def refund_query(self, out_refund_no):
        """
        :param out_refund_no: 退款订单号
        :return:
        """
        url = "/v1/netpay/refund-query"
        content = {"requestTimestamp": self.now_time("%Y-%m-%d %H:%M:%S"),
                   "mid": self.mid,
                   "merOrderId": out_refund_no,
                   "tid": self.tid,
                   "instMid": "YUEDANDEFAULT"
                   }
        Authorization = self.get_token_from_mc()
        header = {
            "Authorization": "OPEN-ACCESS-TOKEN AccessToken=" + Authorization
        }
        return self.post(url, json=content, headers=header)


class YLAppPay(BaseYLClient):
    def __init__(self):
        self.msgSrc = "WWW.TEST.COM"  # 消息来源
        self.mid = "898310148160568"
        self.tid = "00000001"
        self.key = "fcAmtnx7MwismjWNhNKdHC44mNXtnEQeJkRrhKJwyrW2ysRR"

    @property
    def unique_value(self):
        if ONLINE:
            return "6679" + FuncUtils().unique_value  # 外部订单号
        return "3194" + FuncUtils().unique_value  # 外部订单号

    def parameters_add_sign(self, parameters):
        parameters_sorted = sorted(zip(parameters.keys(), parameters.values()))
        data = self.join_and(parameters_sorted)
        sign = hashlib_md5(data + self.key)
        parameters["sign"] = sign.upper()
        return parameters

    def search(self, merOrderId):
        """
        :param msgType: 接口类型 refundQuery 退款查询  query 订单查询
        :param merOrderId: 商户订单号
        :return:
        """
        url = "https://qr-test2.chinaums.com/netpay-route-server/api/"
        msgType = "query"
        now_time = datetime.datetime.now()
        requestTimestamp = now_time.strftime("%Y-%m-%d %H:%M:%S")  # 报文请求时间
        parameters = {
            "msgSrc": self.msgSrc,
            "msgType": msgType,
            "requestTimestamp": requestTimestamp,  # 报文请求时间
            "mid": self.mid,
            "tid": self.tid,
            "merOrderId": merOrderId,
            "signType": "SHA256",
        }

        parameters_sorted = sorted(zip(parameters.keys(), parameters.values()))
        data = self.join_and(parameters_sorted)
        print(data)
        sign = sha256hex(data + self.key)
        parameters["sign"] = sign.upper()
        print(parameters)
        response = self.post(url, json=parameters)
        print(response)
        return response

    def app_pay(self, showUrl, totalAmount, srcReserve="czb", merOrderId=None):
        url = "https://qr-test2.chinaums.com/netpay-route-server/api/"
        msgType = "trade.precreate"
        if not merOrderId:
            merOrderId = self.unique_value  # 商户订单号
        now_time = datetime.datetime.now()
        requestTimestamp = now_time.strftime("%Y-%m-%d %H:%M:%S")  # 报文请求时间
        srcReserve = srcReserve
        mid = self.mid
        tid = self.tid
        key = self.key
        parameters = {
            "msgSrc": self.msgSrc,
            "msgType": msgType,
            "requestTimestamp": requestTimestamp,
            "merOrderId": merOrderId,
            "srcReserve": srcReserve,
            "mid": mid,
            "tid": tid,
            "totalAmount": str(totalAmount),
            "signType": "SHA256",
            "notifyUrl": YLAppNotifyUrl,
            "showUrl": showUrl,
        }
        parameters_sorted = sorted(zip(parameters.keys(), parameters.values()))
        data = self.join_and(parameters_sorted)
        print(data)
        sign = sha256hex(data + key)
        parameters["sign"] = sign.upper()
        print(parameters)
        response = self.post(url, json=parameters)
        print(response)
        return response

    def refund(self, merOrderId, refundAmount, refundOrderId, now_time):
        url = "https://qr-test2.chinaums.com/netpay-route-server/api/"
        msgType = "refund"
        now_time = datetime.datetime.now()
        requestTimestamp = now_time.strftime("%Y-%m-%d %H:%M:%S")  # 报文请求时间
        mid = self.mid
        tid = self.tid
        key = self.key
        parameters = {
            "msgSrc": self.msgSrc,
            "msgType": msgType,
            "requestTimestamp": requestTimestamp,
            "merOrderId": merOrderId,
            "mid": mid,
            "tid": tid,
            "refundAmount": str(refundAmount),
            "signType": "SHA256",
        }
        parameters_sorted = sorted(zip(parameters.keys(), parameters.values()))
        data = self.join_and(parameters_sorted)
        print(data)
        sign = sha256hex(data + key)
        parameters["sign"] = sign.upper()
        print("支付宝APP退款请求数据", parameters)
        response = self.post(url, json=parameters)
        print("支付宝APP退款返回数据", response)
        return response


class ProgramPay(YLAppPay):
    """
    小程序支付
    """

    def get_pay_parameters(self, msgType, totalAmount, srcReserve="czb", notifyUrl=None, returnUrl=None, showUrl=None,
                           openid=None, ali_user_id=None, merOrderId=None):
        """
        :param msgType:
        :param totalAmount:
        :param srcReserve:
        :param notifyUrl:
        :param returnUrl:
        :param showUrl:
        :param openid:
        :param ali_user_id:
        :return:
        """

        if not merOrderId:
            merOrderId = self.unique_value  # 商户订单号
        if not notifyUrl:
            notifyUrl = YLMininotifyUrl
        now_time = datetime.datetime.now()
        requestTimestamp = now_time.strftime("%Y-%m-%d %H:%M:%S")  # 报文请求时间
        parameters = {
            "msgSrc": self.msgSrc,
            "msgType": msgType,
            "requestTimestamp": requestTimestamp,
            "merOrderId": merOrderId,
            "srcReserve": srcReserve,
            "mid": self.mid,
            "tid": self.tid,
            "totalAmount": totalAmount,
            "notifyUrl": notifyUrl,  # 支付结果通知地址
            "returnUrl": returnUrl,  # 网页跳转地址
            "showUrl": showUrl,  # 订单展示页面
            "tradeType": "MINI",  # 交易类型
        }
        if msgType == "wx.unifiedOrder":  # 微信小程序支付
            parameters["subOpenId"] = openid
        elif msgType == "trade.create":  # 支付宝小程序支付
            parameters["userId"] = ali_user_id
        else:
            del parameters["tradeType"]
        return parameters

    def pay(self, parameters):
        url = "https://qr-test2.chinaums.com/netpay-route-server/api/"
        parameters = self.parameters_add_sign(parameters)
        response = self.post(url, json=parameters)
        print(response)
        return parameters, response

    def mini_refund(self, merOrderId, refundAmount, srcReserve="czb"):
        """
        申请退款
        :param merOrderId: 支付时订单号
        :param refundAmount: 退款金额
        :return:
        """
        url = "https://qr-test2.chinaums.com/netpay-route-server/api/"
        now_time = datetime.datetime.now()
        requestTimestamp = now_time.strftime("%Y-%m-%d %H:%M:%S")  # 报文请求时间
        refundOrderId = self.unique_value  # 退款订单号
        parameters = {
            "msgSrc": self.msgSrc,
            "msgType": "refund",
            "requestTimestamp": requestTimestamp,
            "merOrderId": merOrderId,  # 支付时订单号
            "mid": self.mid,
            "tid": self.tid,
            "refundAmount": refundAmount,  # 退款金额
            "refundOrderId": refundOrderId,
            "srcReserve": srcReserve,
        }
        parameters = self.parameters_add_sign(parameters)
        response = self.post(url, json=parameters)
        print(response)
        return parameters, response


class YLOauth(CustomRequests):
    PYTHON_VERSION_3 = True

    def aes_decrypt_content(self, encrypted_content):
        key = "123456789asdfghj"
        aes = AES.new(str.encode(key), AES.MODE_ECB)  # 初始化加密器
        decrypted_text = aes.decrypt(base64.decodebytes(bytes(encrypted_content, encoding='utf8'))).decode("utf8")  # 解密
        decrypted_text = decrypted_text[:-ord(decrypted_text[-1])]  # 去除多余补位
        return decrypted_text

    @property
    def init_sm2(self):
        return sm2.CryptSM2(public_key=self.public_key, private_key=self.private_key)

    # sm2 解密
    def sm2_decrypt(self, data):
        return self.init_sm2.decrypt(data)

    # sm2 加密
    def sm2_encrypt(self, data):
        print(data)
        print(type(data))
        return self.init_sm2.encrypt(data)

    def __init__(self):
        if ONLINE:
            self.base_url = "https://ad.chinaums.com"
            self.public_key = "044774DA78D321CE42AAE6001A31F1BF0522B5BF578D3C31790D0DFBA222E2DE40B5BACB8E2530F29E55D77D629DA96F4135B1637E934E541371767727CB1CBFBE"
            self.private_key = "3133418244880416717548500844444709504898209856981063800207458518484025066376"
        else:
            self.base_url = "https://wxp3.chinaums.com"
            self.public_key = "044774DA78D321CE42AAE6001A31F1BF0522B5BF578D3C31790D0DFBA222E2DE40B5BACB8E2530F29E55D77D629DA96F4135B1637E934E541371767727CB1CBFBE"
            self.private_key = "3133418244880416717548500844444709504898209856981063800207458518484025066376"

    def get_token(self, data):
        """
        :param data: {} 请求数据
        :return:
        """
        url = "https://wxp3.chinaums.com/ecology_dev/web-esp/tradeUnion/tokenCheck/getToken"
        data["time"] = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        response = self.post(url, json=data)
        response = json.loads(response)
        return response

    def check_token(self, data):
        url = "/ecology_dev/web-esp/tradeUnion/tokenCheck/checkToken"
        data["time"] = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        response = self.post(url, json=data)
        # response = json.loads(response)
        return response


yl_app_pay = YLAppPay()
yl_oauth = YLOauth()

# https://shop.kalaibao.com/h5oil/index.html#/pages/login/ylServiceAnth?appId=wx31a9a1934b0570d2&channelId=200714001&cid=ylservice&user_id=194&t=15461
